import { Injectable } from '@nestjs/common'
import { CreateStaffDto } from './dto/create-staff.dto'
import { UpdateStaffDto } from './dto/update-staff.dto'
import { Repository, Equal, Not, IsNull, Like } from 'typeorm'
import { InjectRepository } from '@nestjs/typeorm'
import { Staff } from './entities/staff.entity'
import * as bcrypt from 'bcrypt'
import { LoginStaffDto } from './dto/staff.dto'
import { getBirthday, generateWorkNumber } from './utils'
import { Department } from '../department/entities/department.entity'
import { Job } from '../job/entities/job.entity'
import { WorkState } from '../work-state/entities/work-state.entity'
import {
  EngageFormEnum,
  NationEnum,
  SexEnum,
  WedlockEnum,
  EducationLevelEnum,
  PoliticalAffiliationEnum
} from 'src/types/staff'
import { formatOptionData } from 'src/utils'
import { Admin } from '../admin/entities/admin.entity'
import { Contract } from '../contract/entities/contract.entity'
const moment = require('moment')
@Injectable()
export class StaffService {
  constructor(
    @InjectRepository(Staff) private readonly staff: Repository<Staff>,
    @InjectRepository(Department)
    private readonly department: Repository<Department>,
    @InjectRepository(Job)
    private readonly job: Repository<Job>,
    @InjectRepository(WorkState)
    private readonly workState: Repository<WorkState>,
    @InjectRepository(Admin)
    private readonly admin: Repository<Admin>,
    @InjectRepository(Contract)
    private readonly contract: Repository<Contract>
  ) {}
  async create(createStaffDto: CreateStaffDto) {
    let { password, ...rest } = createStaffDto
    password ?? (password = '123456')
    const salt = await bcrypt.genSalt()
    const hash = await bcrypt.hash(password, salt || 10)
    const birthday = createStaffDto.idCard && getBirthday(createStaffDto.idCard)
    createStaffDto = { password: hash, ...rest, birthday }
    const user = new Staff()
    const department = await this.department.findOne({
      where: { id: createStaffDto.departmentId }
    })
    const job = await this.job.findOne({
      where: {
        id: createStaffDto.jobId
      }
    })
    const workState = await this.workState.findOne({
      where: { id: 1 }
    })
    for (const key in createStaffDto) {
      if (Object.prototype.hasOwnProperty.call(createStaffDto, key)) {
        if (key === 'departmentId') {
          user.department = department
        } else if (key === 'jobId') {
          user.job = job
        } else if (key === 'workStateId') {
          user.workState = workState
        } else {
          user[key] = createStaffDto[key]
        }
      }
    }
    user.workNumber = generateWorkNumber()
    user.workState = workState
    user.endDate = moment(createStaffDto.beginDate)
      .add(createStaffDto.contractDate, 'year')
      .format('YYYY-MM-DD')
    const ok = await this.staff.save(user)
    if (ok) {
      const newContract = new Contract()
      newContract.staff = ok
      newContract.effectiveDate = new Date(createStaffDto.beginDate)
      newContract.jobDescription = ok.job.name + '的工作职责'
      this.contract.save(newContract)
    }
    return ok
  }
  async login(loginStaff: LoginStaffDto) {
    const user = await this.staff.findOne({
      where: {
        phone: Equal(loginStaff.phone)
      }
    })
    if (!user) return null
    const isMatch = await bcrypt.compare(loginStaff.password, user.password)
    if (isMatch) return user
    return null
  }
  async findAllId() {
    return await this.staff.find({ select: ['id'] })
  }

  async findAll(params: {
    page: number
    pageSize: number
    isDelete?: boolean
    departmentId?: number
    jobId?: number
    sex?: string
    name?: string
    workStateId?: number
  }) {
    const where = {}
    params.isDelete && (where['deleteDate'] = Not(IsNull()))
    params.departmentId && (where['department'] = { id: params.departmentId })
    params.jobId && (where['job'] = { id: params.jobId })
    params.sex && (where['sex'] = params.sex)
    params.workStateId && (where['workState'] = { id: params.workStateId })
    params.name && (where['name'] = Like('%' + params.name + '%'))
    const data = await this.staff.find({
      where: { ...where },
      relations: ['department', 'job', 'workState'],
      withDeleted: params.isDelete,
      skip: (params.page - 1) * params.pageSize,
      take: params.pageSize
    })
    const total = await this.staff.count({
      where: { ...where },
      withDeleted: params.isDelete
    })
    const admin = await this.admin.find({
      relations: ['staff', 'role'],
      withDeleted: true
    })
    const newData = []
    data.forEach(item => {
      const {
        id,
        password,
        sex,
        wedlock,
        nation,
        engageForm,
        educationLevel,
        job,
        department,
        workState,
        politicalAffiliation,
        ...rest
      } = item
      const i =
        admin.length > 0
          ? admin.findIndex(i => i.staff && i.staff.id === id)
          : -1
      newData.push({
        ...rest,
        id,
        job: job.name,
        department: department.name,
        workState: workState.name,
        sex: SexEnum[sex],
        wedlock: WedlockEnum[wedlock],
        nation: NationEnum[nation],
        engageForm: EngageFormEnum[engageForm],
        educationLevel: EducationLevelEnum[educationLevel],
        politicalAffiliation: PoliticalAffiliationEnum[politicalAffiliation],
        role:
          i !== -1
            ? {
                id: admin[i].role.id,
                name: admin[i].role.name
              }
            : {
                id: 3,
                name: '员工',
                flag: false
              }
      })
    })
    return { data: newData, total }
  }

  async findAllOption(id: number, type: boolean = false) {
    const data = await this.staff.find({
      where: { job: { id } },
      relations: ['job']
    })
    if (type) return formatOptionData(data)
    const admin = await this.admin.find({ relations: ['staff'] })
    const newData = data.filter(item => {
      const isExist = admin.find(i => i.staff.id === item.id)
      return !isExist
    })
    return formatOptionData(newData)
  }

  async findOne(id: number) {
    const staff = await this.staff.findOne({
      where: { id },
      relations: ['department', 'job', 'workState']
    })
    const admin = await this.admin.findOne({
      where: { staff: { id } },
      relations: ['role', 'staff']
    })
    const {
      password,
      sex,
      wedlock,
      nation,
      engageForm,
      educationLevel,
      job,
      department,
      workState,
      politicalAffiliation,
      ...rest
    } = staff

    return {
      ...rest,
      job: job.name,
      department: department.name,
      workState: workState.name,
      sex: SexEnum[sex],
      wedlock: WedlockEnum[wedlock],
      nation: NationEnum[nation],
      engageForm: EngageFormEnum[engageForm],
      educationLevel: EducationLevelEnum[educationLevel],
      politicalAffiliation: PoliticalAffiliationEnum[politicalAffiliation],
      role: admin ? admin.role.name : '员工'
    }
  }

  async update(id: number, updateStaffDto: UpdateStaffDto) {
    const { departmentId, jobId, workStateId, password, ...rest } =
      updateStaffDto
    const updateStaff: Partial<Staff> = { ...rest }
    if (departmentId) {
      updateStaff.department = await this.department.findOne({
        where: { id: departmentId }
      })
    }
    if (jobId) {
      updateStaff.job = await this.job.findOne({ where: { id: jobId } })
    }
    if (workStateId) {
      updateStaff.workState = await this.workState.findOne({
        where: { id: workStateId }
      })
    }
    if (password) {
      const salt = await bcrypt.genSalt()
      const newPassword = await bcrypt.hash(password, salt || 10)
      updateStaff.password = newPassword
    }
    return this.staff.update(id, updateStaff)
  }

  remove(ids: number[]) {
    return this.staff.softDelete(ids)
  }

  restore(ids: number[]) {
    return this.staff.restore(ids)
  }
}
